#pragma once

#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>

#include "sdkconfig.h"

#include <esp_err.h>
#include <esp_log.h>
#include <esp_system.h>
#include <esp_event.h>
#include <esp32/clk.h>
#include <esp_task_wdt.h>
#include <soc/soc.h>
#include <driver/gpio.h>
#include <driver/uart.h>

#include "std_type.h"
#include "std_err.h"

#ifdef __cplusplus
extern "C" {
#endif


#define INLINE __inline__

#define getPointer(stream) (*((void**)stream))

// ESP32 是小端模式
#define __LITTLE_ENDIAN__ 1

#if (__LITTLE_ENDIAN__ == 1)
	// 网络字节顺序采用 big endian 排序方式
	// 所以如果 MCU 的字节序是 little endian 方式时，需要进行转换
	#define ntoh32(dw) 	BL32(dw)
	#define ntoh16(w) 	BL16(w)
	#define hton32(dw) 	BL32(dw)
	#define hton16(w) 	BL16(w)

	// 从一个字节流中，读取32/16位整数(无符号/有符号)，解决字节对齐问题，同时解决字节序问题
	uint32_t getU32(const void *stream);
	uint16_t getU16(const void *stream);

	#define getS32(stream) ((s32)getU32(stream))
	#define getS16(stream) ((s16)getU16(stream))
#else
	#define ntoh32(dw) 	(dw)
	#define ntoh16(w) 	(w)
	#define hton32(dw) 	(dw)
	#define hton16(w) 	(w)

	// 从一个字节流中，读取32/16位整数(无符号/有符号)，解决字节对齐问题，同时解决字节序问题
	#define getU32(stream) (*((uint32_t*)stream))
	#define getU16(stream) (*((uint16_t*)stream))

	#define getS32(stream) (*((s32*)stream))
	#define getS16(stream) (*((s16*)stream))
#endif


/// @brief 关闭所有中断
#define disableInterrupts() 	taskDISABLE_INTERRUPTS()
/// @brief 打开所有中断
#define enableInterrupts()		taskENABLE_INTERRUPTS()
/// @brief 当前是否在中断中
#define osIsInIsr() 			xPortInIsrContext()

/**
 * @brief 关于临界区
 * FreeRTOS@ESP32 有几种层次的临界区：
 * 硬件级：硬件(仅可屏蔽的)中断开关: portDISABLE_INTERRUPTS() / portENABLE_INTERRUPTS() =实现=> taskDISABLE_INTERRUPTS() / taskENABLE_INTERRUPTS()
 * 任务级：可在任务执行过程中禁止任务切换: vTaskSuspendAll() / xTaskResumeAll()
 * 资源级: 仅针对指定资源进行保护: vTaskEnterCritical() / vTaskExitCritical() =实现=> portENTER_CRITICAL() / portEXIT_CRITICAL() =代替=> taskENTER_CRITICAL() / taskEXIT_CRITICAL()
 * NONOS 中的 osCritical 是针对单个资源级的
 * 关于 vTaskEnterCritical() 可能导致的问题，请参见：
 * @see https://docs.espressif.com/projects/esp-idf/zh_CN/latest/api-guides/freertos-smp.html#critical-sections-disabling-interrupts
 */
/*
// 用 portENTER_CRITICAL()/portEXIT_CRITICAL() 的实现会关闭中断，导致很多场景下无法使用，放弃！
#define osCritical           portMUX_TYPE
//#define osCriticalInitValue  portMUX_INITIALIZER_UNLOCKED
#define osCriticalInitValue  {portMUX_FREE_VAL, 0}
#define osCriticalDef(css)   osCritical (css) = osCriticalInitValue
#define osCriticalEnter(css) portENTER_CRITICAL_SAFE(&(css))
#define osCriticalLeave(css) portEXIT_CRITICAL_SAFE(&(css))
*/
// 改为 用 Binary 型的 Semaphore 实现
#define osCritical           QueueHandle_t
#define osCriticalInitValue  xSemaphoreCreateBinary()
#define osCriticalDef(css)   osCritical (css) = osCriticalInitValue
#define osCriticalEnter(css) xSemaphoreTake(css, (TickType_t)100)
#define osCriticalLeave(css) xSemaphoreGive(css)

/// @brief 在关闭中断的状态下执行代码
#define osExecWithouInterrupt(x)	do { disableInterrupts(); (x); enableInterrupts(); } while(0)


#define ESP_INTR_FLAG_DEFAULT 0

#ifdef ESP8266
    /**
     * 与 ESP32-IDF 保持一致
     */
    #define GPIO_PIN_INTR_DISABLE    GPIO_INTR_DISABLE
    #define GPIO_PIN_INTR_POSEDGE    GPIO_INTR_POSEDGE
    #define GPIO_PIN_INTR_NEGEDGE    GPIO_INTR_NEGEDGE
    #define GPIO_PIN_INTR_ANYEDGE    GPIO_INTR_ANYEDGE
    #define GPIO_PIN_INTR_LOW_LEVEL  GPIO_INTR_LOW_LEVEL
    #define GPIO_PIN_INTR_HIGH_LEVEL GPIO_INTR_HIGH_LEVEL
    #define GPIO_PIN_INTR_MAX        GPIO_INTR_MAX
#endif // ESP8266

typedef enum {
	GPIO_MODEX_NULL = 0,  // 禁用
	GPIO_MODEX_IPU,       // 上拉输入
	GPIO_MODEX_IPD,       // 下拉输入
	GPIO_MODEX_OPPL,      // 推挽输出，初始输出低电平
	GPIO_MODEX_OPPH,      // 推挽输出，初始输出高电平
	GPIO_MODEX_OODL,      // 开漏输出，初始输出低电平
	GPIO_MODEX_OODH,      // 开漏输出，初始输出高电平
	GPIO_MODEX_MAX
} gpio_modex_t;

/**
 * 参数版 gpio_config()
 */
esp_err_t GPIO_Config(gpio_num_t pin, gpio_mode_t mode, gpio_pullup_t pull_up_en, gpio_pulldown_t pull_down_en, gpio_int_type_t intr_type);
esp_err_t GPIO_ConfigX(gpio_num_t pin, gpio_modex_t mode, gpio_int_type_t intr);

/**
 * GPIO APIs 函数类型声明
 */
typedef esp_err_t (*FUNC_GPIO_ConfigX)(gpio_modex_t mode, gpio_int_type_t intr_type);
typedef esp_err_t (*FUNC_GPIO_Config)(gpio_mode_t mode, gpio_pullup_t pull_up_en, gpio_pulldown_t pull_down_en, gpio_int_type_t intr_type);
typedef esp_err_t (*FUNC_GPIO_Toggle)();
typedef int       (*FUNC_GPIO_In)();
typedef esp_err_t (*FUNC_GPIO_Out)(uint8_t x);
typedef esp_err_t (*FUNC_GPIO_IntEnable)(gpio_int_type_t trig);
typedef esp_err_t (*FUNC_GPIO_IntDisable)();
typedef esp_err_t (*FUNC_GPIO_Switch)(uint8_t x);

/**
 * 声明命名的 GPIO APIs(基本的)
 */
#define GPIO_DECLARE(NAME) \
	extern const gpio_num_t GPIO_##NAME; \
	esp_err_t GPIO_##NAME##_ConfigX(gpio_modex_t mode, gpio_int_type_t intr_type); \
	esp_err_t GPIO_##NAME##_Config(gpio_mode_t mode, gpio_pullup_t pull_up_en, gpio_pulldown_t pull_down_en, gpio_int_type_t intr_type); \
	void      GPIO_##NAME##_Toggle(); \
	uint8_t        GPIO_##NAME##_In(); \
	void      GPIO_##NAME##_Out(uint8_t x); \
	esp_err_t GPIO_##NAME##_IntEnable(gpio_int_type_t trig); \
	esp_err_t GPIO_##NAME##_IntDisable(); \
	esp_err_t GPIO_##NAME##_IntRegisterIsr(gpio_isr_t isr_handler, void* args); \
	esp_err_t GPIO_##NAME##_IntRemoveIsr();

/**
 * 声明命名的 GPIO APIs(带极性的)
 */
#define GPIO_DECLARE_POLARITY(NAME) \
	GPIO_DECLARE(NAME) \
	extern const int GPIO_##NAME##_TRIG_LEVEL; \
	void      GPIO_##NAME##_On(); \
	void      GPIO_##NAME##_Off(); \
	void      GPIO_##NAME##_Switch(uint8_t on); \
	uint8_t   GPIO_##NAME##_IsInOn(); \
	uint8_t   GPIO_##NAME##_IsInOff(); \
	uint8_t   GPIO_##NAME##_Polarity();


/**
 * 定义命名的 GPIO APIs(基本的)
 */
#define GPIO_DEFINE(NAME, PIN) \
	const gpio_num_t GPIO_##NAME                            = PIN; \
	esp_err_t GPIO_##NAME##_ConfigX(gpio_modex_t mode, gpio_int_type_t intr_type) { return GPIO_ConfigX(PIN, mode, intr_type); } \
	esp_err_t GPIO_##NAME##_Config(gpio_mode_t mode, gpio_pullup_t pull_up_en, gpio_pulldown_t pull_down_en, gpio_int_type_t intr_type) \
															{ return GPIO_Config(PIN, mode, pull_up_en, pull_down_en, intr_type); } \
	void      GPIO_##NAME##_Toggle()                        { gpio_set_level(PIN, !gpio_get_level(PIN)); } \
	uint8_t        GPIO_##NAME##_In()                            { return gpio_get_level(PIN); } \
	void      GPIO_##NAME##_Out(uint8_t x)                       { gpio_set_level(PIN, x); } \
	esp_err_t GPIO_##NAME##_IntEnable(gpio_int_type_t trig) { return gpio_set_intr_type(PIN, trig); } \
	esp_err_t GPIO_##NAME##_IntDisable()                    { return gpio_set_intr_type(PIN, GPIO_INTR_DISABLE); } \
	esp_err_t GPIO_##NAME##_IntRegisterIsr(gpio_isr_t isr_handler, void* args) \
															{ return gpio_isr_handler_add(PIN, isr_handler, args); } \
	esp_err_t GPIO_##NAME##_IntRemoveIsr()      	        { return gpio_isr_handler_remove(PIN); }

/**
 * 定义命名的 GPIO APIs(带极性的)
 */
#define GPIO_DEFINE_POLARITY(NAME, PIN, LEVEL) \
	GPIO_DEFINE(NAME, PIN) \
	const int GPIO_##NAME##_TRIG_LEVEL						= LEVEL; \
	void      GPIO_##NAME##_On()          			        { GPIO_##NAME##_Out(LEVEL); } \
	void      GPIO_##NAME##_Off()         				    { GPIO_##NAME##_Out(!LEVEL); } \
	void      GPIO_##NAME##_Switch(uint8_t on) 				    { (!on == !LEVEL)?GPIO_##NAME##_Out(1):GPIO_##NAME##_Out(0); } \
	uint8_t        GPIO_##NAME##_IsInOn()      				    { return (GPIO_##NAME##_In() == LEVEL); } \
	uint8_t        GPIO_##NAME##_IsInOff()     				    { return (GPIO_##NAME##_In() != LEVEL); } \
	uint8_t        GPIO_##NAME##_Polarity()      			    { return LEVEL; }

/**
 * 外部中断触发类型
 typedef enum {
    GPIO_INTR_DISABLE = 0,     // Disable GPIO interrupt
    GPIO_INTR_POSEDGE = 1,     // GPIO interrupt type : rising edge
    GPIO_INTR_NEGEDGE = 2,     // GPIO interrupt type : falling edge
    GPIO_INTR_ANYEDGE = 3,     // GPIO interrupt type : both rising and falling edge
    GPIO_INTR_LOW_LEVEL = 4,   // GPIO interrupt type : input low level trigger
    GPIO_INTR_HIGH_LEVEL = 5,  // GPIO interrupt type : input high level trigger
    GPIO_INTR_MAX,
} gpio_int_type_t;
*/
typedef enum {
	EXTI_Trigger_Disable = GPIO_INTR_DISABLE,
	EXTI_Trigger_Rising = GPIO_INTR_POSEDGE,
	EXTI_Trigger_Falling = GPIO_INTR_NEGEDGE,
	EXTI_Trigger_Rising_Falling = GPIO_INTR_ANYEDGE,
} EXTI_Trigger_TypeDef;


//
// 简单的中断重入及性能统计
//
/// 中断编号
typedef enum {
	//Interrupt hardware source table
	//This table is decided by hardware, don't touch this.
	IRQn_WIFI_MAC_INTR        = ETS_WIFI_MAC_INTR_SOURCE,       // 0:  interrupt of WiFi MAC, level
	IRQn_WIFI_MAC_NMI         = ETS_WIFI_MAC_NMI_SOURCE,        // 1:  interrupt of WiFi MAC, NMI, use if MAC have bug to fix in NMI
	IRQn_WIFI_BB_INTR         = ETS_WIFI_BB_INTR_SOURCE,        // 2:  interrupt of WiFi BB, level, we can do some calibartion
	IRQn_BT_MAC_INTR          = ETS_BT_MAC_INTR_SOURCE,         // 3:  will be cancelled
	IRQn_BT_BB_INTR           = ETS_BT_BB_INTR_SOURCE,          // 4:  interrupt of BT BB, level
	IRQn_BT_BB_NMI            = ETS_BT_BB_NMI_SOURCE,           // 5:  interrupt of BT BB, NMI, use if BB have bug to fix in NMI
	IRQn_RWBT_INTR            = ETS_RWBT_INTR_SOURCE,           // 6:  interrupt of RWBT, level
	IRQn_RWBLE_INTR           = ETS_RWBLE_INTR_SOURCE,          // 7:  interrupt of RWBLE, level
	IRQn_RWBT_NMI             = ETS_RWBT_NMI_SOURCE,            // 8:  interrupt of RWBT, NMI, use if RWBT have bug to fix in NMI
	IRQn_RWBLE_NMI            = ETS_RWBLE_NMI_SOURCE,           // 9:  interrupt of RWBLE, NMI, use if RWBT have bug to fix in NMI
	IRQn_SLC0_INTR            = ETS_SLC0_INTR_SOURCE,           // 10: interrupt of SLC0, level
	IRQn_SLC1_INTR            = ETS_SLC1_INTR_SOURCE,           // 11: interrupt of SLC1, level
	IRQn_UHCI0_INTR           = ETS_UHCI0_INTR_SOURCE,          // 12: interrupt of UHCI0, level
	IRQn_UHCI1_INTR           = ETS_UHCI1_INTR_SOURCE,          // 13: interrupt of UHCI1, level
	IRQn_TG0_T0_LEVEL_INTR    = ETS_TG0_T0_LEVEL_INTR_SOURCE,   // 14: interrupt of TIMER_GROUP0, TIMER0, level, we would like use EDGE for timer if permission
	IRQn_TG0_T1_LEVEL_INTR    = ETS_TG0_T1_LEVEL_INTR_SOURCE,   // 15: interrupt of TIMER_GROUP0, TIMER1, level, we would like use EDGE for timer if permission
	IRQn_TG0_WDT_LEVEL_INTR   = ETS_TG0_WDT_LEVEL_INTR_SOURCE,  // 16: interrupt of TIMER_GROUP0, WATCHDOG, level
	IRQn_TG0_LACT_LEVEL_INTR  = ETS_TG0_LACT_LEVEL_INTR_SOURCE, // 17: interrupt of TIMER_GROUP0, LACT, level
	IRQn_TG1_T0_LEVEL_INTR    = ETS_TG1_T0_LEVEL_INTR_SOURCE,   // 18: interrupt of TIMER_GROUP1, TIMER0, level, we would like use EDGE for timer if permission
	IRQn_TG1_T1_LEVEL_INTR    = ETS_TG1_T1_LEVEL_INTR_SOURCE,   // 19: interrupt of TIMER_GROUP1, TIMER1, level, we would like use EDGE for timer if permission
	IRQn_TG1_WDT_LEVEL_INTR   = ETS_TG1_WDT_LEVEL_INTR_SOURCE,  // 20: interrupt of TIMER_GROUP1, WATCHDOG, level
	IRQn_TG1_LACT_LEVEL_INTR  = ETS_TG1_LACT_LEVEL_INTR_SOURCE, // 21: interrupt of TIMER_GROUP1, LACT, level
	IRQn_GPIO_INTR            = ETS_GPIO_INTR_SOURCE,           // 22: interrupt of GPIO, level
	IRQn_GPIO_NMI             = ETS_GPIO_NMI_SOURCE,            // 23: interrupt of GPIO, NMI
	IRQn_FROM_CPU_INTR0       = ETS_FROM_CPU_INTR0_SOURCE,      // 24: interrupt0 generated from a CPU, level /* Used for FreeRTOS
	IRQn_FROM_CPU_INTR1       = ETS_FROM_CPU_INTR1_SOURCE,      // 25: interrupt1 generated from a CPU, level /* Used for FreeRTOS
	IRQn_FROM_CPU_INTR2       = ETS_FROM_CPU_INTR2_SOURCE,      // 26: interrupt2 generated from a CPU, level /* Used for DPORT Access
	IRQn_FROM_CPU_INTR3       = ETS_FROM_CPU_INTR3_SOURCE,      // 27: interrupt3 generated from a CPU, level /* Used for DPORT Access
	IRQn_SPI0_INTR            = ETS_SPI0_INTR_SOURCE,           // 28: interrupt of SPI0, level, SPI0 is for Cache Access, do not use this
	IRQn_SPI1_INTR            = ETS_SPI1_INTR_SOURCE,           // 29: interrupt of SPI1, level, SPI1 is for flash read/write, do not use this
	IRQn_SPI2_INTR            = ETS_SPI2_INTR_SOURCE,           // 30: interrupt of SPI2, level
	IRQn_SPI3_INTR            = ETS_SPI3_INTR_SOURCE,           // 31: interrupt of SPI3, level
	IRQn_I2S0_INTR            = ETS_I2S0_INTR_SOURCE,           // 32: interrupt of I2S0, level
	IRQn_I2S1_INTR            = ETS_I2S1_INTR_SOURCE,           // 33: interrupt of I2S1, level
	IRQn_UART0_INTR           = ETS_UART0_INTR_SOURCE,          // 34: interrupt of UART0, level
	IRQn_UART1_INTR           = ETS_UART1_INTR_SOURCE,          // 35: interrupt of UART1, level
	IRQn_UART2_INTR           = ETS_UART2_INTR_SOURCE,          // 36: interrupt of UART2, level
	IRQn_SDIO_HOST_INTR       = ETS_SDIO_HOST_INTR_SOURCE,      // 37: interrupt of SD/SDIO/MMC HOST, level
	IRQn_ETH_MAC_INTR         = ETS_ETH_MAC_INTR_SOURCE,        // 38: interrupt of ethernet mac, level
	IRQn_PWM0_INTR            = ETS_PWM0_INTR_SOURCE,           // 39: interrupt of PWM0, level, Reserved
	IRQn_PWM1_INTR            = ETS_PWM1_INTR_SOURCE,           // 40: interrupt of PWM1, level, Reserved
	IRQn_PWM2_INTR            = ETS_PWM2_INTR_SOURCE,           // 41: interrupt of PWM2, level
	IRQn_PWM3_INTR            = ETS_PWM3_INTR_SOURCE,           // 42: interruot of PWM3, level
	IRQn_LEDC_INTR            = ETS_LEDC_INTR_SOURCE,           // 43: interrupt of LED PWM, level
	IRQn_EFUSE_INTR           = ETS_EFUSE_INTR_SOURCE,          // 44: interrupt of efuse, level, not likely to use
	IRQn_CAN_INTR             = ETS_CAN_INTR_SOURCE,            // 45: interrupt of can, level
	IRQn_RTC_CORE_INTR        = ETS_RTC_CORE_INTR_SOURCE,       // 46: interrupt of rtc core, level, include rtc watchdog
	IRQn_RMT_INTR             = ETS_RMT_INTR_SOURCE,            // 47: interrupt of remote controller, level
	IRQn_PCNT_INTR            = ETS_PCNT_INTR_SOURCE,           // 48: interrupt of pluse count, level
	IRQn_I2C_EXT0_INTR        = ETS_I2C_EXT0_INTR_SOURCE,       // 49: interrupt of I2C controller1, level
	IRQn_I2C_EXT1_INTR        = ETS_I2C_EXT1_INTR_SOURCE,       // 50: interrupt of I2C controller0, level
	IRQn_RSA_INTR             = ETS_RSA_INTR_SOURCE,            // 51: interrupt of RSA accelerator, level
	IRQn_SPI1_DMA_INTR        = ETS_SPI1_DMA_INTR_SOURCE,       // 52: interrupt of SPI1 DMA, SPI1 is for flash read/write, do not use this
	IRQn_SPI2_DMA_INTR        = ETS_SPI2_DMA_INTR_SOURCE,       // 53: interrupt of SPI2 DMA, level
	IRQn_SPI3_DMA_INTR        = ETS_SPI3_DMA_INTR_SOURCE,       // 54: interrupt of SPI3 DMA, level
	IRQn_WDT_INTR             = ETS_WDT_INTR_SOURCE,            // 55: will be cancelled
	IRQn_TIMER1_INTR          = ETS_TIMER1_INTR_SOURCE,         // 56: will be cancelled
	IRQn_TIMER2_INTR          = ETS_TIMER2_INTR_SOURCE,         // 57: will be cancelled
	IRQn_TG0_T0_EDGE_INTR     = ETS_TG0_T0_EDGE_INTR_SOURCE,    // 58: interrupt of TIMER_GROUP0, TIMER0, EDGE
	IRQn_TG0_T1_EDGE_INTR     = ETS_TG0_T1_EDGE_INTR_SOURCE,    // 59: interrupt of TIMER_GROUP0, TIMER1, EDGE
	IRQn_TG0_WDT_EDGE_INTR    = ETS_TG0_WDT_EDGE_INTR_SOURCE,   // 60: interrupt of TIMER_GROUP0, WATCH DOG, EDGE
	IRQn_TG0_LACT_EDGE_INTR   = ETS_TG0_LACT_EDGE_INTR_SOURCE,  // 61: interrupt of TIMER_GROUP0, LACT, EDGE
	IRQn_TG1_T0_EDGE_INTR     = ETS_TG1_T0_EDGE_INTR_SOURCE,    // 62: interrupt of TIMER_GROUP1, TIMER0, EDGE
	IRQn_TG1_T1_EDGE_INTR     = ETS_TG1_T1_EDGE_INTR_SOURCE,    // 63: interrupt of TIMER_GROUP1, TIMER1, EDGE
	IRQn_TG1_WDT_EDGE_INTR    = ETS_TG1_WDT_EDGE_INTR_SOURCE,   // 64: interrupt of TIMER_GROUP1, WATCHDOG, EDGE
	IRQn_TG1_LACT_EDGE_INTR   = ETS_TG1_LACT_EDGE_INTR_SOURCE,  // 65: interrupt of TIMER_GROUP0, LACT, EDGE
	IRQn_MMU_IA_INTR          = ETS_MMU_IA_INTR_SOURCE,         // 66: interrupt of MMU Invalid Access, LEVEL
	IRQn_MPU_IA_INTR          = ETS_MPU_IA_INTR_SOURCE,         // 67: interrupt of MPU Invalid Access, LEVEL
	IRQn_CACHE_IA_INTR        = ETS_CACHE_IA_INTR_SOURCE,       // 68: interrupt of Cache Invalied Access, LEVEL
	IRQn_MAX
} IRQn;

/// 中断重入层级
extern uint8_t _IrqReentry[IRQn_MAX];
/// 中断重入层级曾经的最大值
extern uint8_t _IrqReentryMax;
/// 当前在中断的第几层(如果中断嵌套的话)
#define osIrqStack(id)	(_IrqReentry[(id)])
/// 进入中断/临界区后马上调用
#define osIrqEnter(id)	(_IrqReentry[(id)]++, _IrqReentryMax = MAX(_IrqReentryMax, _IrqReentry[(id)]))
/// 退出中断/临界区前调用
#define osIrqLeave(id)	(--_IrqReentry[(id)])

/// 是否处于调试状态
#define osIsInDebugMode() 	esp_cpu_in_ocd_debug_mode()
/// 获得重启原因
#define osGetResetReason() 	esp_reset_reason()
/// 是否是非正常重启
bool osIsAbnormalReboot();
/**
 * 获取 EFUSE 中的默认 MAC 地址<br>
 * 默认情况下，ESP32 会在此 MAC 地址基础上自动生成 WiFi.STA / WiFi.AP / Bluetooth / Ethernet 的 MAC 地址，依次加 1
 */
esp_err_t osGetDefaultMac(uint8_t mac[6]);

/// SHIP2 通信接口类型定义
/// 此接口是指 网关<-->MFRC 通信时，MFRC侧可能会有多个接口
typedef enum {
    Ship2IfType_NULL       = 0x0,   ///< 未知
    Ship2IfType_P2P   	   = 0x1,   ///< P2P通信接口(如 UART/SPI 等)
    Ship2IfType_P2MP       = 0x2,   ///< 点对多点通信接口(如 RS485/I2C 等)
    Ship2IfType_RFComm     = 0x3,   ///< RFComm(CC110X)
    Ship2IfType_TCP        = 0x4,   ///< TCPSocket
    Ship2IfType_UDP        = 0x5,   ///< UDPSocket
    Ship2IfType_SPP        = 0x6,   ///< 蓝牙 SPP
    Ship2IfType_BLEBeacon  = 0x7,   ///< 蓝牙(BLE模式)iBeacon
    Ship2IfType_WiFiBeacon = 0x8,   ///< WiFi Beacon
    Ship2IfType_LoRa       = 0x9,   ///< LoRa串口透传
    Ship2IfType_Zigbee     = 0xA,   ///< Zigbee
    Ship2IfType_RF433      = 0xB,   ///< 433遥控
    Ship2IfType_RF315      = 0xC,   ///< 315遥控
    Ship2IfType_IR         = 0xD,   ///< 红外遥控
    Ship2IfType_HXDIR      = 0xE,   ///< HXD红外遥控
    Ship2IfType_MAX        = 0xF    ///< 非法值/ALL(指所有接口)
} Ship2IfType;

/// 是否是 P2P 接口
#define Ship2IfType_IS_P2P(ifType) ((ifType) == Ship2IfType_P2P || (ifType) == Ship2IfType_TCP || (ifType) == Ship2IfType_SPP)
#define Ship2If_IS_P2P(link) 		Ship2IfType_IS_P2P(link->ifType())

/// SHIP2 固定长度通信地址长度定义
typedef enum {
    Ship2AddrSize_NULL      = 0x0,   ///< 未知(默认0字节地址)
    Ship2AddrSize_P2P       = 0x0,   ///< 点对点(无地址)
    Ship2AddrSize_RFComm    = 0x4,   ///< RFComm(定长4字节)
    Ship2AddrSize_I2C       = 0x4,   ///< I2C(定长4字节)
    Ship2AddrType_IP4Port   = 0x6,   ///< IPv4(定长6字节地址:IP+Port)
    Ship2AddrSize_MAX       = 0xF    ///< 最大地址长度
} Ship2AddrSize;

/// SHIP2 固定长度通信地址类型定义(接口类型+固定地址长度)
typedef enum {
    Ship2AddrType_NULL      = MAKE_BYTE(Ship2IfType_NULL, 0),   ///< 未知
	Ship2AddrType_P2P		= MAKE_BYTE(Ship2IfType_P2P, 0),   	///< UART(点对点传送，无地址)
	Ship2AddrType_P2MP		= MAKE_BYTE(Ship2IfType_P2MP, 4),   ///< RS485主从串口、/I2C 等点对多点传送地址，4字节地址为 devId
    Ship2AddrType_RFComm    = MAKE_BYTE(Ship2IfType_RFComm, 4), ///< RFComm(分组传送，4字节地址为 devId)
    Ship2AddrType_TCP       = MAKE_BYTE(Ship2IfType_TCP, 6),   	///< TCPSocket(点对点通信，6字节地址为 IP:PORT)
    Ship2AddrType_UDP       = MAKE_BYTE(Ship2IfType_UDP, 6),   	///< UDPSocket(点对点多点通信，6字节地址为 IP:PORT)
    Ship2AddrType_MAX       = MAKE_BYTE(Ship2IfType_MAX, 0)     ///< 非法值/广播
} Ship2AddrType;

/// 通信地址
#pragma pack(push, 1)   //{{
typedef union unShip2Addr {
    // 标准地址格式
	struct {
        uint8_t addrSize:4;                  ///< 设备地址长度
        Ship2IfType ifType:4;           ///< 接口类型
        uint8_t devAddr[16];                 ///< 设备地址(实际长度为 addrSize)
    } st;

    struct {
    	uint32_t devId:32;					///< 只有 RFComm 的原始数据帧中才是这样，没有地址类型，只有设备ID
    } rfcommRaw;

    // 4 字节 devId 地址
    struct {
        Ship2AddrType type:8;           ///< 地址类型: Ship2AddrType_P2MP/Ship2AddrType_RFComm/Ship2AddrType_I2C
        uint32_t devId:32;
    } num, rfcomm, rs485, i2c;

    // 6 字节 IPv4:PORT
    struct {
        Ship2AddrType type:8;           ///< 地址类型: Ship2AddrType_TCP/Ship2AddrType_UDP
        uint32_t ipv4:32;					///< IPv4 地址
        uint16_t port:16;					///< 端口号(网络字节序)
    } tcp, udp;

    // 字节流格式
    uint8_t bytes[17];
} Ship2Addr;
#pragma pack(pop)       //}}


/// 常用内置硬件接口地址
extern const Ship2Addr Ship2Addr_NULL ;
extern const Ship2Addr Ship2Addr_UART0;
extern const Ship2Addr Ship2Addr_UART1;
extern const Ship2Addr Ship2Addr_UART2;
extern const Ship2Addr Ship2Addr_UART3;
extern const Ship2Addr Ship2Addr_UART4;
extern const Ship2Addr Ship2Addr_UART5;
extern const Ship2Addr Ship2Addr_SPI0 ;
extern const Ship2Addr Ship2Addr_SPI1 ;
extern const Ship2Addr Ship2Addr_SPI2 ;
extern const Ship2Addr Ship2Addr_SPI3 ;
extern const Ship2Addr Ship2Addr_I2C0 ;
extern const Ship2Addr Ship2Addr_I2C1 ;
extern const Ship2Addr Ship2Addr_I2C2 ;
extern const Ship2Addr Ship2Addr_I2C3 ;

/// 本机地址常量
extern const Ship2Addr Ship2Addr_P2P;

/// 广播地址常量
extern const Ship2Addr Ship2BroadcastAddr_ALL;			// 表示向所有的接口进行广播
extern const Ship2Addr Ship2BroadcastAddr_ALL_P2P;		// 表示向所有的 P2P 接口进行广播
extern const Ship2Addr Ship2BroadcastAddr_ALL_P2MP;	// 表示向所有的 P2MP 接口进行广播
extern const Ship2Addr Ship2BroadcastAddr_ALL_RFComm;	// 表示向所有的 RFComm 接口进行广播

extern const Ship2Addr Ship2BroadcastAddr_P2P;			// P2P 地址实际上没有广播，就是 P2P 地址
extern const Ship2Addr Ship2BroadcastAddr_P2MP;		// 向 P2MP 接口上的所有设备广播
extern const Ship2Addr Ship2BroadcastAddr_RFComm;		// 向 RFComm 接口上的所有设备广播


/// 转化为字符串
/// @attention 注意：此函数不支持多任务安全！如在同一个 printf() 中两次使用此函数，第一次的返回字符串会被第二次的覆盖！
const char* Ship2Addr_toString(const Ship2Addr* addr);
/// 比较2个通信地址是否是相同的
bool Ship2Addr_same(const Ship2Addr* addr1, const Ship2Addr* addr2);
/// 把地址2拷贝到地址1中去
void Ship2Addr_copy(Ship2Addr* addr1, const Ship2Addr* addr2);


/// 编码类型
typedef enum {
	RcCodeType_RAW			= 0x0,	///< 原始编码
	RcCodeType_PULSE_INDEX	= 0x1,	///< 脉冲索引码
	RcCodeType_BIT			= 0x2,	///< BIT码
	RcCodeType_HXDIR		= 0x4,	///< 宏信达 红外
	RcCodeType_MAX			= 0x5,	///< 宏信达 红外
} RcCodeType;

/// 获取编码类型名称
const char* getRcCodeTypeName(RcCodeType type);

/// 遥控接口类型
typedef enum {
	RcIfType_NULL = 0x0,///< 无
	RcIfType_RF315,		///< 315 MHz
	RcIfType_RF433,		///< 433 MHz
	RcIfType_IR,		///< Ir 红外
	RcIfType_HXDIR,		///< 宏信达 红外
	RcIfType_MAX,		///< 无效值
} RcIfType;

/// 获取遥控接口类型名称
const char* getRcIfTypeName(RcIfType type);


/// 初始化 Key-Value 存储
esp_err_t nvs_init();
/// 获取 NVS 数据长度
int nvs_blob_length(const char* ns, const char* name);
/// 加载 NVS 数据(自动分配缓冲区内存，长度为实际存储长度)
void* nvs_blob_load(const char* ns, const char* name, int* len);
/// 加载 NVS 数据(使用指定缓冲区，长度固定)
esp_err_t nvs_blob_load_into(const char* ns, const char* name, void* data, int len);
/// 保存 NVS 数据
esp_err_t nvs_blob_save(const char* ns, const char* name, const void* data, int len);
/// 删除 NVS 数据
esp_err_t nvs_blob_erase(const char* ns, const char* name);

/// MCU 初始化
void mcu_init();


#ifdef __cplusplus
}
#endif
